#include"bmpfunc.h"

static int checkHeader(BMP_Header * hdr){

    if(MAGIC_VALUE != (hdr)->type){

        printf("check magic value failed.\n");
        return 0;
    }
    if(BITS_PER_PIXEL != (hdr)->bits){
        
        printf("check BITS_PER_PIXEL failed bits = %d.\n",hdr->bits);
        return 0;
    }
    if(NUM_PLANE!=hdr->planes){

        printf("check NUM_PLANE failed.\n");
        return 0;
    }
    if(COMPRESSION!=hdr->compress){

        printf("check COMPRESSION failed,COMPRESSION = %d.\n",hdr->compress);
        return 0;
    }
    return 1;
}

BMP_Image * cleanUp(FILE * fptr,BMP_Image * img){

    if(NULL != fptr){

        fclose(fptr);
    }
    if(NULL == img){

        if(NULL!=img->data){

            free(img->data);
        }
        free(img);
    }
}

BMP_Image * BMP_open(const char * filename){

    FILE * fptr = NULL;
    BMP_Image * img = NULL;
    fptr = fopen(filename,"r");
    if(NULL==fptr){

        printf("open %s failed.\n",filename);
        return NULL;
    }
    img = (BMP_Image*)malloc(sizeof(BMP_Image));
    if(NULL==img){

        printf("malloc BMP_Image failed.\n");
        // -close hdl,free memory and return null
        return cleanUp(fptr,img);
    }
    // -read the header
    if(fread(&(img->header),sizeof(BMP_Header),1,fptr)!=1){

        printf("read header failed.\n");
        return cleanUp(fptr,img);
    }
    if(0 == checkHeader(&(img->header))){

        printf("check header failed.\n");
        return cleanUp(fptr,img);
    }
    img->data_size = (img)->header.size - sizeof(BMP_Header);
    img->width     = (img->header).widtd;
    img->height    = (img->header).height;
    img->bites_per_pixel = (img->header).bits / BITS_PER_BYTE;
    img->data      = malloc(sizeof(unsigned char)*img->data_size);

    if(NULL == img->data){

        return cleanUp(fptr,img);
    }
    if(fread((img->data),sizeof(char),img->data_size,fptr)!=img->data_size){

        return cleanUp(fptr,img);
    }
    char onebyte;
    if(fread(&onebyte,sizeof(char),1,fptr)!=0){

        return cleanUp(fptr,img);
    }
    fclose(fptr);
    return img;
}

int BMP_save(const BMP_Image * img,const char * filename){

    FILE * fptr = NULL;
    fptr = fopen(filename,"w");
    if(NULL == fptr){

        printf("open %s failed.\n",filename);
        return 0;
    }
    if(fwrite(&(img->header),sizeof(BMP_Header),1,fptr)!=1){

        fclose(fptr);
        return 0;
    }
    if(fwrite(img->data,sizeof(char),img->data_size,fptr)!=img->data_size){

        fclose(fptr);
        return 0;
    }
    fclose(fptr);
    return 1;
}

void BMP_destroy(BMP_Image * img){

    free(img->data);
    free(img);
}

void BMP_order(BMP_Image * img,int cls){

    for(int index = 0;index < img->data_size;index++){

        // -将其他 均设置为0
        if(index%3 != cls){

            img->data[index] = 0;
        }
    }
    BMP_save(img,"first.bmp");
}

void BMP_color_mirror(BMP_Image * img){

    for(int index = 0;index < img->data_size;index++){

        img->data[index] = 255 - img->data[index];
    }
    BMP_save(img,"two.bmp");
}

void BMP_equalize(BMP_Image * img){

    int pxl;
    unsigned char redmin = 255;
    unsigned char redmax = 0;
    unsigned char bluemin = 255;
    unsigned char bluemax = 0;
    unsigned char greenmin = 255;
    unsigned char greenmax = 0;

    for(pxl = 0;pxl < img->data_size;pxl+=3){

        unsigned char red = img->data[pxl + 2];
        unsigned char green = img->data[pxl + 1];
        unsigned char blue = img->data[pxl];

        if(red > redmax) {  redmax = red;   }
        if(red < redmin) {  redmin = red;   }
        
        if(blue > bluemax){ bluemax = blue; }
        if(blue < bluemin){ bluemin = blue; }

        if(green > greenmax){   greenmax = green;   }
        if(green < greenmin){   greenmin = green;   }
    }

    double redscale = 0.0;
    double greenscale = 0.0;
    double bluescale = 0.0;

    if(redmax > redmin){

        redscale = 255.0 / (redmax - redmin);
    }
    if(greenmax > greenmin){

        greenscale = 255.0 / (greenmax - greenmin);
    }
    if(bluemax > bluemin){

        bluescale = 255.0 / (bluemax - bluemin);
    }
    for(pxl = 0;pxl < img->data_size;pxl+=3){

        if(redmax > redmin){

            img->data[pxl+2] = (int)redscale*(img->data[pxl+2] - redmin);
        }
        if(greenmax > greenmax){

            img->data[pxl+1] = (int)greenscale * (img->data[pxl+1]-greenmin);
        }
        if(bluemax > bluemin){

            img->data[pxl] = (int)bluescale*(img->data[pxl] - bluemin);
        }
    }
    BMP_save(img,"three.bmp");
}